package org.richin.orm.hibernate.util;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.hibernate.persister.entity.AbstractEntityPersister;
import org.hibernate.persister.entity.SingleTableEntityPersister;

import org.hibernate.EntityMode;
import org.hibernate.SessionFactory;
import org.hibernate.metadata.ClassMetadata;
import org.richin.array.util.ArrayUtils;

/**
 * hibernate 辅助工具类
 *
 * @author ronald
 */
public class HibernateUtil {
	   /**
     * 取得数据库中的所有表名
     *
     * @return
     */
    @SuppressWarnings("unchecked")
	public List<String> getAllDbTableName(SessionFactory sessionFactory) {
            List<String> resultList = new ArrayList<String>();
            Map metaMap = sessionFactory.getAllClassMetadata();
            for (String key : (Set<String>) metaMap.keySet()) {
                    AbstractEntityPersister classMetadata = (SingleTableEntityPersister) metaMap
                                    .get(key);
                    resultList.add(classMetadata.getTableName());
            }
            return resultList;
    }


        /**
         * 根据映射类和属性名得到数据库的字段名
         *
         * @param sessionFactory
         * @param clazz 映射类(DTO)
         * @param fieldName 属性名
         * @return
         */
        public static String[] getColumnNames(SessionFactory sessionFactory,
                        Class<?> clazz, String fieldName) {
                AbstractEntityPersister ep = getEntityPersisterByClassName(
                                sessionFactory, clazz);
                if (ep != null) {
                        return ep.getPropertyColumnNames(fieldName);
                }
                return null;
        }

        /**
         * 根据映射类和属性名得到数据库的字段名
         *
         * @param sessionFactory
         * @param clazz 映射类(DTO)
         * @param fieldName 属性名
         * @return
         */
        public static String getColumnName(SessionFactory sessionFactory,
                        Class<?> clazz, String fieldName) {
                String[] columnNames = getColumnNames(sessionFactory, clazz, fieldName);
                if (ArrayUtils.isNotEmpty(columnNames)) {
                        return columnNames[0];
                }
                return null;
        }

        /**
         * 根据映射类得到表名
         *
         * @param sessionFactory
         * @param clazz
         * @return
         */
        public static String getTableName(SessionFactory sessionFactory,
                        Class<?> clazz) {
                AbstractEntityPersister ep = getEntityPersisterByClassName(
                                sessionFactory, clazz);
                if (ep != null) {
                        ep.getTableName();
                }
                return null;
        }

        /**
         * 得到主键名字段名
         *
         * @param sessionFactory
         * @param clazz 映射类(DTO)
         * @return 主键的字段名,如果为多个则表示为组合主键
         */
        public static String[] getPKColumnNames(SessionFactory sessionFactory,
                        Class<?> clazz) {
                AbstractEntityPersister ep = getEntityPersisterByClassName(
                                sessionFactory, clazz);
                if (ep != null) {
                        ep.getKeyColumnNames();
                }

                return null;
        }

        /**
         * 得到主键名字段名
         *
         * @param sessionFactory
         * @param clazz 映射类(DTO)
         * @return 主键的字段名
         */
        public static String getPKColumnName(SessionFactory sessionFactory,
                        Class<?> clazz) {
                String[] names = getPKColumnNames(sessionFactory, clazz);
                if (ArrayUtils.isNotEmpty(names)) {
                        return names[0];
                }
                return null;
        }

        /**
         * 得到主键的属性名
         *
         * @param sessionFactory
         * @param clazz 映射类(DTO)
         * @return
         */
        public static String getPKFieldName(SessionFactory sessionFactory,
                        Class<?> clazz) {
                AbstractEntityPersister ep = getEntityPersisterByClassName(
                                sessionFactory, clazz);
                if (ep != null) {
                        return ep.getIdentifierPropertyName();
                }

                return null;
        }

        /**
         * 根据表名和字段名得到对方映射类中的属性名
         *
         * @param sessionFactory
         * @param tableName 表名
         * @param columnName 字段名
         * @return 对应的属性名
         */
        public static String getFieldName(SessionFactory sessionFactory,
                        String tableName, String columnName) {
                if (columnName == null) {
                        return null;
                }
                AbstractEntityPersister ep = getEntityPersisterByTableName(
                                sessionFactory, tableName);
                if (ep != null) {
                        String[] names = ep.getPropertyNames();
                        for (String n : names) {
                                String[] name = ep.getPropertyColumnNames(n);
                                if (ArrayUtils.isNotEmpty(name)) {
                                        if (name[0].equalsIgnoreCase(columnName)) {
                                                return n;
                                        }
                                }
                        }
                }
                return null;
        }
        /**
         * 取得对象中所有映射的列名
         *
         * @param objClass
         * @return
         */
        public List<String> getDbCellName(SessionFactory factory,Class<?> objClass) {
                List<String> resultList = new ArrayList<String>();
                Class<?> cls = objClass;
                AbstractEntityPersister classMetadata = (SingleTableEntityPersister) factory
                                .getClassMetadata(cls);
                // 添加主键
                resultList.addAll(Arrays.asList(classMetadata
                                .getIdentifierColumnNames()));
                String[] propertyNames = classMetadata.getPropertyNames();
                for (String propertyName : propertyNames) {
                        // 判断是否一对多的对像,移除
                        boolean isCollection = classMetadata.getClassMetadata()
                                        .getPropertyType(propertyName).isCollectionType();
                        if (!isCollection) {
                                String[] propertyColumnNames = classMetadata
                                                .getPropertyColumnNames(propertyName);
                                for (String columnName : propertyColumnNames) {
                                        resultList.add(columnName);
                                }
                        }
                }
                return resultList;
        }
        /**
         * 按列名与对像取出映射对象的字段
         *
         * @param objClass
         * @param columnName
         * @return
         */
        public String getPropertyByColunm(SessionFactory factory,Class<?> objClass, String columnName) {
                AbstractEntityPersister classMetadata = (SingleTableEntityPersister) factory
                                .getClassMetadata(objClass);
                String[] propertyNames = classMetadata.getPropertyNames();
                for (String propertyName : propertyNames) {
                        // 判断是否一对多的对像,移除
                        boolean isCollection = classMetadata.getClassMetadata()
                                        .getPropertyType(propertyName).isCollectionType();
                        if (!isCollection) {
                                String[] propertyColumnNames = classMetadata
                                                .getPropertyColumnNames(propertyName);
                                for (String tempColumnName : propertyColumnNames) {
                                        if (columnName.equals(tempColumnName)) {
                                                return propertyName;
                                        }
                                }
                        }
                }
                return null;
        }

        /**
         * 按列名与对像取出映射对像的类型(不包括主键)
         *
         * @param objClass
         * @param columnName
         * @return
         */
        public Class<?> getPropertyTypeByColumn(SessionFactory factory,Class<?> objClass, String columnName) {
                String propertyName = getPropertyByColunm(factory,objClass, columnName);
                AbstractEntityPersister classMetadata = (SingleTableEntityPersister) factory
                                .getClassMetadata(objClass);
                return classMetadata.getPropertyType(propertyName).getReturnedClass();
        }

        /**
         * 根据表名和字段名得到对方映射类中的属性名
         *
         * @param sessionFactory
         * @param clazz 映射类(DTO)
         * @param columnName 字段名
         * @return 对应的属性名
         */
        public static String getFieldName(SessionFactory sessionFactory,
                        Class<?> clazz, String columnName) {
                AbstractEntityPersister ep = getEntityPersisterByClassName(
                                sessionFactory, clazz);
                if (ep != null) {
                        String[] names = ep.getPropertyNames();
                        for (String n : names) {
                                String[] name = ep.getPropertyColumnNames(n);
                                if (ArrayUtils.isNotEmpty(name)) {
                                        if (name[0].equalsIgnoreCase(columnName)) {
                                                return n;
                                        }
                                }
                        }
                }
                return null;
        }

        /**
         * 根据表名得到映射类(DTO)
         *
         * @param sessionFactory
         * @param tableName 表名
         * @return
         */
        public static Class<?> getMappedClassByTableName(
                        SessionFactory sessionFactory, String tableName) {
                AbstractEntityPersister ep = getEntityPersisterByTableName(
                                sessionFactory, tableName);
                if (ep != null) {
                        return ep.getMappedClass(EntityMode.POJO);
                        // return ep.getName();
                }
                return null;
        }

        private static AbstractEntityPersister getEntityPersisterByClassName(
                        SessionFactory sessionFactory, Class<?> clazz) {
                if (sessionFactory == null || clazz == null) {
                        return null;
                }

                ClassMetadata meta = sessionFactory.getClassMetadata(clazz);
                if (meta == null) {
                        return null;
                }
                if (meta instanceof AbstractEntityPersister) {
                        return (AbstractEntityPersister) meta;
                }

                return null;

        }

        @SuppressWarnings("unchecked")
        private static AbstractEntityPersister getEntityPersisterByTableName(
                        SessionFactory sessionFactory, String tableName) {
                if (sessionFactory == null || tableName == null) {
                        return null;
                }
                Map<String, ClassMetadata> metas = sessionFactory.getAllClassMetadata();
                if (metas == null) {
                        return null;
                }
                ClassMetadata meta = null;
                for (String key : metas.keySet()) {
                        meta = metas.get(key);
                        if (meta == null) {
                                continue;
                        }
                        if (meta instanceof AbstractEntityPersister) {
                                AbstractEntityPersister ep = (AbstractEntityPersister) meta;
                                if (ep.getTableName().equalsIgnoreCase(tableName)) {
                                        return ep;
                                }
                        }
                }

                return null;
        }
        /**
         * 是否有指定的数据表
         *
         * @param tableName
         * @return
         */
        public boolean isExistTableName(SessionFactory sessionFactory,String tableName) {
                List<String> allTableNameList = getAllDbTableName(sessionFactory);
                for (String tempTableName : allTableNameList) {
                        if (tableName.equals(tempTableName)) {
                                return true;
                        }
                }
                return false;
        }

}
